package com.skivingcloud.admin.sys.service.impl;

import com.skivingcloud.admin.sys.entity.AppRouteRecordRaw;
import com.skivingcloud.admin.sys.entity.MenuBean;
import com.skivingcloud.admin.sys.entity.MenuMeta;
import com.skivingcloud.admin.sys.entity.SysCommUseMenu;
import com.skivingcloud.admin.sys.entity.SysMenu;
import com.skivingcloud.admin.sys.entity.SysMenuClickLog;
import com.skivingcloud.admin.sys.entity.User;
import com.skivingcloud.admin.sys.mapper.SysCommUseMenuMapper;
import com.skivingcloud.admin.sys.mapper.SysMenuClickLogMapper;
import com.skivingcloud.admin.sys.mapper.SysMenuMapper;
import com.skivingcloud.admin.sys.service.ISysMenuService;
import com.skivingcloud.common.contants.Constant;
import com.skivingcloud.common.utils.StringUtils;
import com.skivingcloud.common.utils.TreeUtils;
import com.skivingcloud.common.utils.UuidUtil;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import net.sf.json.JSONObject;

/**
 * <p>
 * 菜单管理 服务实现类
 * </p>
 *
 * @author skivingcloud
 * @since 2022-01-29
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

	@Autowired
	private SysCommUseMenuMapper sysCommUseMenuMapper;
	@Autowired
	private SysMenuClickLogMapper sysMenuClickLogMapper;

	@Override
	public List<MenuBean> getUserMenuList(String id, String terminal, String sessionId) {
		List<String> menuIdList = new ArrayList<String>();
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("id", id);
		param.put("terminal", terminal);
		List<Map<String, Object>> list2 = this.baseMapper.selectUserMenuListMap(param);
		for (Map<String, Object> map : list2) {
			menuIdList.add(map.get("id").toString());
		}
		return getAllMenuList(menuIdList, sessionId);
	}

	/**
	 * 
	 * @param menuIdList
	 * @param sessionId
	 * @return
	 */
	private List<MenuBean> getAllMenuList(List<String> menuIdList, String sessionId) {
		// 查询根菜单列表
		List<MenuBean> menuList = queryListParentId("0", menuIdList);
		// 递归获取子菜单
		getMenuTreeList(menuList, menuIdList, sessionId);

		return menuList;
	}

	@Override
	public Set<String> getUserPermissions(String id, String terminal) {
		Set<String> permsSet = new HashSet<String>();
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("id", id);
		param.put("menuType1", Constant.MenuType.BUTTON.getValue());
		param.put("menuType2", Constant.MenuType.MENU.getValue());
		List<Map<String, Object>> list2 = this.baseMapper.getUserPermissions(param);
		for (Map map : list2) {
			if (StringUtils.isBlank(map.get("perms"))) {
				continue;
			}
			permsSet.addAll(Arrays.asList(map.get("perms").toString().trim().split(",")));
		}
		return permsSet;
	}

	@Override
	public List<Map<String, Object>> getCommUseMenuSetTree(String id, String terminal) {
		if (Constant.TerminalType.TERMINALTYPE_PC.getValue().equals(terminal)) {
			Map<String, Object> param = new HashMap<String, Object>();
			param.put("id", id);
			param.put("menuType", Constant.MenuType.BUTTON.getValue());
			param.put("terminal", terminal);
			List<Map<String, Object>> list = this.baseMapper.getCommUseMenuSetTreeStation(param);
			list.addAll(this.baseMapper.getCommUseMenuSetTreeRole(param));
			return list;
		} else {
			return null;
		}
	}

	@Override
	public List<MenuBean> getMenuCheckList(String id, String terminal) {
		return this.baseMapper.getMenuCheckList(id);
	}

	@Override
	public void saveCommUseMenu(String[] ids, User user) {
		QueryWrapper<SysCommUseMenu> queryWrapper = new QueryWrapper<SysCommUseMenu>();
		queryWrapper.eq("user_id", user.getId());
		sysCommUseMenuMapper.delete(queryWrapper);
		for (String id : ids) {
			SysCommUseMenu sysCommUseMenu = new SysCommUseMenu();
			sysCommUseMenu.setId(UuidUtil.get32UUID());
			sysCommUseMenu.setResId(id);
			sysCommUseMenu.setUserId(user.getId());
			sysCommUseMenuMapper.insert(sysCommUseMenu);
		}
	}

	@Override
	public List<MenuBean> getCommUseMenuTreeByTerminal(String id, String[] terminals) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("userId", id);
		map.put("terminals", Arrays.asList(terminals));
		return this.baseMapper.queryCommUseMenuListByTerminal(map);
	}

	@Override
	public List<MenuBean> queryListParentId(String parentId, List<String> menuIdList) {
		List<MenuBean> menuList = queryListParentId(parentId);
		if (menuIdList == null) {
			return menuList;
		}

		List<MenuBean> userMenuList = new ArrayList<MenuBean>();
		for (MenuBean menu : menuList) {
			if (menuIdList.contains(menu.getId())) {
				userMenuList.add(menu);
			}
		}
		return userMenuList;
	}

	@Override
	public List<MenuBean> queryListParentId(String parentId) {
		QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<SysMenu>();
		queryWrapper.eq("parent_id", parentId);
		List<SysMenu> list = this.baseMapper.selectList(queryWrapper);
		return list.stream().map(m -> {
			MenuBean menuBean = new MenuBean();
			menuBean.setAlias(m.getAlias());
			menuBean.setIcon(m.getIcon());
			menuBean.setId(m.getId());
			menuBean.setName(m.getName());
			menuBean.setOrderNum(m.getOrderNum());
			menuBean.setParentId(m.getParentId());
			menuBean.setPerms(m.getPerms());
			menuBean.setSysResource(m.getSysResource());
			menuBean.setType(m.getType());
			menuBean.setUrl(m.getUrl());
			return menuBean;
		}).collect(Collectors.toList());
	}

	/**
	 * 递归
	 */
	private List<MenuBean> getMenuTreeList(List<MenuBean> menuList, List<String> menuIdList) {
		List<MenuBean> subMenuList = new ArrayList<MenuBean>();

		for (MenuBean entity : menuList) {
			// 目录
			if (entity.getType() == Constant.MenuType.CATALOG.getValue()) {
				entity.setList(getMenuTreeList(queryListParentId(entity.getId(), menuIdList), menuIdList));
			}
			subMenuList.add(entity);
		}

		return subMenuList;
	}

	/**
	 * 递归,系统外资源拼接sessionid
	 * 
	 * @param menuList
	 * @param menuIdList
	 * @param sessionId
	 */
	private List<MenuBean> getMenuTreeList(List<MenuBean> menuList, List<String> menuIdList, String sessionId) {
		List<MenuBean> subMenuList = new ArrayList<MenuBean>();

		for (MenuBean entity : menuList) {
			// 目录
			if (entity.getType() == Constant.MenuType.CATALOG.getValue()) {
				entity.setList(getMenuTreeList(queryListParentId(entity.getId(), menuIdList), menuIdList, sessionId));
			}
			subMenuList.add(entity);
		}

		return subMenuList;
	}

	/**
	 * 记录用户菜单点击
	 * 
	 * @param menuId
	 * @param user
	 * @throws Exception
	 */
	@Override
	public void menuClick(String menuId, User user) throws Exception {
		SysMenuClickLog clickLog = new SysMenuClickLog();
		clickLog.setId(UuidUtil.get32UUID());
		clickLog.setMenuId(menuId);
		clickLog.setUserId(user.getId());
		clickLog.setOperTime(LocalDateTime.now());
		sysMenuClickLogMapper.insert(clickLog);
	}

	/**
	 * 根据菜单终端类型获取菜单树，如果不是超级管理员只返回自己租户的资源
	 * 
	 * @param terminals 终端
	 * @param user
	 * @return
	 * @throws Exception
	 */
	@Override
	public List<TreeUtils> gerResTreeByTerminal(List<String> terminals, User user) throws Exception {
		QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<SysMenu>();
		if (!user.getTenantId().equals(Constant.SUPER_ADMIN_TENANTID)) {
			// paramsNew.put("tenantId", user.getTenantId());
			queryWrapper.eq("tenant_id", user.getTenantId());
		}
		queryWrapper.orderByAsc("order_num");
		List<SysMenu> list = this.baseMapper.selectList(queryWrapper);
		List<TreeUtils> treeList = TreeUtils.getTreeList(list, "id", "parentId", "name", null, null);
		return treeList;
	}

	/**
	 * 列表查询
	 * 
	 * @param obj
	 * @return
	 */
	@Override
	public List<SysMenu> selectList(JSONObject obj) {
		QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<SysMenu>();
		if (obj.containsKey("terminal")) {
			String objTerminal = obj.get("terminal") == null ? "" : obj.get("terminal").toString();
			if (StringUtils.isNotBlank(objTerminal)) {
				queryWrapper.in("terminal", Arrays.asList(objTerminal.split(",")));
			}
		}
		queryWrapper.orderByAsc("order_num");
		List<SysMenu> list = this.baseMapper.selectList(queryWrapper);
		return list;
	}

	@Override
	public List<MenuBean> queryNotButtonList() {
		return this.baseMapper.queryNotButtonList(Constant.MenuType.BUTTON.getValue());
	}

	@Override
	@CacheEvict(value = "menus", key = "'menulistTree'")
	@Transactional(rollbackFor = Exception.class)
    public void insert(SysMenu menu) {
		menu.setId(UuidUtil.get32UUID());
		if (StringUtils.isBlank(menu.getSysResource())) {
			menu.setSysResource("1");
		}
		this.baseMapper.insert(menu);
	}

	@Override
	@CacheEvict(value = "menus", key = "'menulistTree'")
	@Transactional(rollbackFor = Exception.class)
    public void updateByIdMe(SysMenu menu) {
		this.baseMapper.updateById(menu);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@CacheEvict(value = "menus", key = "'menulistTree'")
	public void delete(String id) {
		// 删除菜单
		this.baseMapper.deleteById(id);
	}

	@Override
	public List<AppRouteRecordRaw> getUserMenuListRoute(String id, String terminal, String sessionId) {
		List<String> menuIdList = new ArrayList<String>();
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("id", id);
		param.put("terminal", terminal);
		List<Map<String, Object>> list2 = this.baseMapper.selectUserMenuListMap(param);
		for (Map<String, Object> map : list2) {
			menuIdList.add(map.get("id").toString());
		}
		return getAllMenuListRoute(menuIdList, sessionId);
	}

	private List<AppRouteRecordRaw> getAllMenuListRoute(List<String> menuIdList, String sessionId) {
		QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<SysMenu>();
		queryWrapper.in("id", menuIdList);
		List<SysMenu> list = this.baseMapper.selectList(queryWrapper);

		// 查询根菜单列表
		List<AppRouteRecordRaw> menuList = list.stream().filter(n -> Constant.MenuType.MENU.getValue() == n.getType())
				.map(m -> {
					AppRouteRecordRaw menuBean = new AppRouteRecordRaw();
					menuBean.setId(m.getId());
					menuBean.setType(m.getType());
					menuBean.setName(m.getUrl() == null ? m.getName() : m.getUrl().replace('/', '-'));
					if ("0".equals(m.getSysResource())) {
						menuBean.setComponent("#");
					} else {
						menuBean.setComponent(m.getUrl() == null ? "#" : "views/modules/" + m.getUrl());
					}
					menuBean.setPath(m.getUrl() == null ? "/dashboard" : "/" + m.getUrl().replace('/', '-'));
					menuBean.setRedirect(m.getUrl() == null ? "/dashboard/analysis" : "noredirect");
					MenuMeta menuMeta = new MenuMeta();
					// menuMeta.setActiveMenu(parentId);
					menuMeta.setAffix(false);
					menuMeta.setAlwaysShow(false);
					menuMeta.setBreadcrumb(false);
					menuMeta.setCanTo(false);
					// menuMeta.setFollowAuth(parentId);
					menuMeta.setHidden(false);
					menuMeta.setIcon(m.getIcon());
					menuMeta.setNoCache(false);
					menuMeta.setNoTagsView(false);
					menuMeta.setTitle(m.getName());
					menuBean.setMeta(menuMeta);
					return menuBean;
				}).collect(Collectors.toList());
		return menuList;
	}

	private List<AppRouteRecordRaw> queryListParentIdRoute(String parentId, List<String> menuIdList) {
		List<AppRouteRecordRaw> menuList = queryListParentIdRoute(parentId);
		if (menuIdList == null) {
			return menuList;
		}
		List<AppRouteRecordRaw> userMenuList = new ArrayList<AppRouteRecordRaw>();
		for (AppRouteRecordRaw menu : menuList) {
			if (menuIdList.contains(menu.getId())) {
				userMenuList.add(menu);
			}
		}
		return userMenuList;
	}

	private List<AppRouteRecordRaw> queryListParentIdRoute(String parentId) {
		QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<SysMenu>();
		queryWrapper.eq("parent_id", parentId);
		List<SysMenu> list = this.baseMapper.selectList(queryWrapper);
		List<AppRouteRecordRaw> listBean = list.stream().map(m -> {
			AppRouteRecordRaw menuBean = new AppRouteRecordRaw();
			menuBean.setId(m.getId());
			menuBean.setType(m.getType());
			menuBean.setName(m.getUrl() == null ? m.getName() : m.getUrl().replace('/', '-'));
			if ("0".equals(m.getSysResource())) {
				menuBean.setComponent("#");
			} else {
				menuBean.setComponent(m.getUrl() == null ? "#" : "views/modules/" + m.getUrl());
			}
			menuBean.setPath(m.getUrl() == null ? "/dashboard" : m.getUrl().replace('/', '-'));
			menuBean.setRedirect(m.getUrl() == null ? "/dashboard/analysis" : "");
			MenuMeta menuMeta = new MenuMeta();
			// menuMeta.setActiveMenu(parentId);
			menuMeta.setAffix(false);
			menuMeta.setAlwaysShow(false);
			menuMeta.setBreadcrumb(false);
			menuMeta.setCanTo(false);
			// menuMeta.setFollowAuth(parentId);
			menuMeta.setHidden(false);
			menuMeta.setIcon(m.getIcon());
			menuMeta.setNoCache(false);
			menuMeta.setNoTagsView(false);
			menuMeta.setTitle(m.getName());
			menuBean.setMeta(menuMeta);
			return menuBean;
		}).collect(Collectors.toList());
		return listBean;
	}

	/**
	 * 递归
	 * @param menuList
	 * @param menuIdList
	 * @param sessionId
	 */
	private List<AppRouteRecordRaw> getMenuTreeListRoute(List<AppRouteRecordRaw> menuList, List<String> menuIdList,
			String sessionId) {
		List<AppRouteRecordRaw> subMenuList = new ArrayList<AppRouteRecordRaw>();

		for (AppRouteRecordRaw entity : menuList) {
			// 目录
			if (entity.getType() == Constant.MenuType.CATALOG.getValue()) {
				entity.setChildren(getMenuTreeListRoute(queryListParentIdRoute(entity.getId(), menuIdList), menuIdList,
						sessionId));
			}
			subMenuList.add(entity);
		}

		return subMenuList;
	}

	@Override
	public List<Map<String, Object>> getUserMenuListData(String id, String terminal) {
		List<String> menuIdList = new ArrayList<String>();
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("id", id);
		param.put("terminal", terminal);
		List<Map<String, Object>> list2 = this.baseMapper.selectUserMenuListMap(param);
		for (Map<String, Object> map : list2) {
			menuIdList.add(map.get("id").toString());
		}
		return getAllMenuListData(menuIdList);
	}

	private List<Map<String, Object>> getAllMenuListData(List<String> menuIdList) {
		List<Map<String, Object>> menuList = new ArrayList<Map<String, Object>>();
		// 先添加一个首页菜单
		Map<String, Object> mapHome = new HashMap<String, Object>();
		mapHome.put("path", "/home");
		mapHome.put("name", "home");
		mapHome.put("component", "home/index");
		Map<String, Object> mapHomeMeta = new HashMap<String, Object>();
		mapHomeMeta.put("title", "首页");
		mapHomeMeta.put("isLink", "");
		mapHomeMeta.put("isHide", false);
		mapHomeMeta.put("isKeepAlive", true);
		mapHomeMeta.put("isAffix", true);
		mapHomeMeta.put("isIframe", false);
		mapHomeMeta.put("roles", new String[] { "admin", "common" });
		mapHomeMeta.put("icon", "iconfont icon-shouye");
		mapHome.put("meta", mapHomeMeta);
		menuList.add(mapHome);
		// 查询根菜单列表
		List<Map<String, Object>> menuList1 = queryListParentIdData("0", menuIdList);
		// 递归获取子菜单
		getMenuTreeListData(menuList1, menuIdList);
		menuList.addAll(menuList1);
		
		return menuList;
	}

	private List<Map<String, Object>> queryListParentIdData(String parentId, List<String> menuIdList) {
		List<Map<String, Object>> menuList = queryListParentIdData(parentId);
		if (menuIdList == null) {
			return menuList;
		}

		List<Map<String, Object>> userMenuList = new ArrayList<>();
		userMenuList.addAll(
				menuList.stream().filter(m -> menuIdList.contains(m.get("id"))).collect(Collectors.toList()));
		return userMenuList;
	}

	private List<Map<String, Object>> queryListParentIdData(String parentId) {
		QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("parent_id", parentId);
		queryWrapper.orderByAsc("order_num");
		List<SysMenu> list = this.baseMapper.selectList(queryWrapper);
		return list.stream().map(m -> {
			Map<String, Object> menuBean = new HashMap<>();
			menuBean.put("id", m.getId());
			menuBean.put("type", m.getType());
			if (m.getUrl().indexOf("/:") > -1) {
				// menuBean.put("path", "/" + m.getUrl());
				menuBean.put("path", "/" + m.getUrl().substring(0, m.getUrl().indexOf("/:")) + "/:t/:id/:tagsViewName");
				menuBean.put("name", m.getUrl().substring(0, m.getUrl().indexOf("/:")).replace('/', '-'));
				menuBean.put("component", m.getUrl().substring(0, m.getUrl().indexOf("/:")));
				String[] ppp = m.getUrl().substring(m.getUrl().indexOf("/:"), m.getUrl().length()).split("/:");
				Map<String, String> mppp = new HashMap<>();
				mppp.put("t", ppp[1]);
				mppp.put("id", ppp[2]);
				mppp.put("tagsViewName", ppp[3]);
				menuBean.put("params", mppp);
			} else {
				menuBean.put("path", "/" + m.getUrl());
				menuBean.put("name", m.getUrl().replace('/', '-'));
				menuBean.put("component", m.getUrl());
			}
			if (m.getRedirect() != null) {
				menuBean.put("redirect", m.getRedirect());
			}
			Map<String, Object> menuBeanMeta = new HashMap<>();
			menuBeanMeta.put("title", m.getName());
			if (Constant.COMMON_YES_OR_NO_NO.equals(m.getSysResource())) {
				menuBeanMeta.put("isLink", m.getUrl());
			}
			menuBeanMeta.put("isHide", Constant.COMMON_YES_OR_NO_YES.equals(m.getIsHide()));
			menuBeanMeta.put("isKeepAlive", Constant.COMMON_YES_OR_NO_YES.equals(m.getIsKeepAlive()));
			menuBeanMeta.put("isAffix", Constant.COMMON_YES_OR_NO_YES.equals(m.getIsAffix()));
			menuBeanMeta.put("isIframe", Constant.COMMON_YES_OR_NO_NO.equals(m.getSysResource()));
			menuBeanMeta.put("roles", new String[] { "admin" });
			menuBeanMeta.put("icon", m.getIcon());
			/* if (m.getUrl().indexOf("/:") > -1) {
				String[] ppp = m.getUrl().substring(m.getUrl().indexOf("/:"), m.getUrl().length()).split("/:");
				Map<String, String> mppp = new HashMap<>();
				mppp.put("t", ppp[1]);
				mppp.put("id", ppp[2]);
				mppp.put("tagsViewName", ppp[3]);
				menuBeanMeta.put("params", mppp);
			} */
			menuBean.put("meta", menuBeanMeta);
			return menuBean;
		}).collect(Collectors.toList());
	}

	private List<Map<String, Object>> getMenuTreeListData(List<Map<String, Object>> menuList, List<String> menuIdList) {
		List<Map<String, Object>> subMenuList = new ArrayList<Map<String, Object>>();

		for (Map<String, Object> entity : menuList) {
			// 目录
			if ((Integer)entity.get("type") == Constant.MenuType.CATALOG.getValue()) {
				entity.put("children", getMenuTreeListData(queryListParentIdData(entity.get("id").toString(), menuIdList), menuIdList));
			}
			subMenuList.add(entity);
		}

		return subMenuList;
	}
}
